﻿/**
 * @filename TabScroller.js
 * @author baboo
 * @description	多标签的显示控制
 */
 
 /**
  * Dom方法扩展，并将其绑定到Dollar对象的单元素默认方法中
  */
$.Dom.extend ({
	/**
	 * 移动s个像素的距离
	 */	
	horMoveBy : function (e, s, sets) {
		var originX = parseInt(e.style.left, 10) || 0;
		$.Dom['_horMoveTo'](e, originX + s, sets);
	},
	/**
	 * 移动到x坐标的位置
	 */
	horMoveTo : function (e, x, sets) {
		var originX = parseInt(e.style.left, 10) || 0, sets = sets || {};
		var deltaX = x - originX;
		if (deltaX == 0) return;
		if (e.effectObj) $.Effect.remove(e.effectObj);
		var effect = $.effect({
			onFinish: function () {
				e.style.left = x + 'px';
			},
			render: function(pos) {
				e.style.left = (originX + deltaX * pos) + 'px';
			},
			duration:0.5
		});
		$.extend(effect, sets);
		$.Effect.add(effect);
		e.effectObj = effect;
	}	
}, false, [false, false]);

/**
 * @class $.TabScoller
 * @description:
 *	标签的HTML定义的层次格式类下：
 *	<div> <div class="box"><div class="tab">标签1</div><div class="tab">标签2</div></div></div>
 *	sets 是一个配制对象，对象的参数有
 *	required	$long	: 	标签元素的父级容器(Dollar)对象
 *	required	$tabs	:	标签(Dollar)对象
 *	required	$limit	:	标签显示的限制容器(Dollar)对象
 *	optional	mode	:	标签滚动的模式 "one" 一次滚动一个标签, "group" 一次滚动一栏标签	默认为"one"
 *	optional	hideMode:	当mode="group"时，设置了该参数则最后一个不完整显示的标签被截去
 *	optional	useEffect:		是否使用移动效果，默认为false	
 * $date:2008-12-18$ : 修改参数名称，使用更为准确的参数名 $limit => $limit, $long => $long
 */
$.TabScroller = $({
	__init : function (sets) {
		var $long = sets.$long, $tabs = sets.$tabs, mode = sets.mode || 'one', hideMode = sets.hideMode || false;
		if (!$long.length || !$tabs.length || !sets.$limit.length) return;
		var cntW = sets.$limit.$('offsetWidth');
		var baseX = $long.$('offsetLeft');
		var posInfo = [0], startIndex = 0, endIndex = -1;
		for (var i = 0, len = $tabs.length; i < len; i++) {
			var endX = ($tabs[i].offsetLeft - baseX) + $tabs[i].offsetWidth;
			posInfo.push(endX);
			if (endX > cntW) {
				mode == 'group' && hideMode && $tabs.$(i, '$hide');
				if (endIndex == -1) {
					endIndex = i;
				}
			}
		}
		if (endIndex == -1) return;
		this.hasNav = false;
		if (endIndex < $tabs.length) {
			this.hasNav = true;
			var btnsInfo = sets.navBtnsInfo;
			if (btnsInfo) {
				btnsInfo.$pre.$('$class', '+' + btnsInfo.disabledClass).show();
				btnsInfo.$next.show();	
			}
		}
		this.cntW = cntW;
		this.posInfo = posInfo;
		this.$tabs = sets.$tabs;
		this.$long = sets.$long;
		this.startIndex = startIndex;
		this.endIndex = endIndex;
		this.mode = mode;
		this.useEffect = sets.useEffect || false;
		this.hideMode = hideMode;
		this.sets = sets;
		if (sets.initTabIndex) this.scrollIntoView(sets.initTabIndex);
	}, 
	destroy : function () {
			
	},
	next : function (evt) {
		evt && $(evt, 'stop');
		this.mode == 'one' ? this.__nextOne() : this.__nextGroup();	
	},
	pre : function (evt) {
		evt && $(evt, 'stop');
		this.mode == 'one' ? this.__preOne() : this.__preGroup();
	},
	//should be  called to init the tab status only
	scrollIntoView : function (tabIndex) {
		if (tabIndex >= this.$tabs.length || tabIndex < this.endIndex) return;
		var newStartIndex = this.__getStartIndex(tabIndex + 1, this.posInfo, this.cntW);
		this.__nextOne(newStartIndex - this.startIndex);
		//this.__nextOne(tabIndex - this.endIndex + 1);
	},
	__nextOne : function (ones) {
		var $tabs = this.$tabs, ones = ones || 1;
		if (this.endIndex == $tabs.length) return;
		var toX = - this.posInfo[this.startIndex + ones];
		if (this.useEffect) {
			this.$long.horMoveTo(toX, this.sets.effectSets);
		} else {
			this.$long.css('left:' + toX + 'px');
		}
		this.startIndex += ones;
		this.endIndex = this.__getEndIndex(this.startIndex, this.posInfo, this.cntW);
		this.hasNav && this.__setBtnStatus();
	},
	__preOne : function () {
		var $tabs = this.$tabs;
		if (this.startIndex == 0) return;
		this.startIndex--;
		var toX = - this.posInfo[this.startIndex];
		if (this.useEffect) {
			this.$long.horMoveTo(toX, this.sets.effectSets);	
		} else {
			this.$long.css('left:' + toX + 'px');
		}
		this.endIndex = this.__getEndIndex(this.startIndex, this.posInfo, this.cntW); 	
		this.hasNav && this.__setBtnStatus();
	},
	__nextGroup : function () {
		var $tabs = this.$tabs, posInfo = this.posInfo;
		if (this.endIndex == $tabs.length) return;
		this.startIndex = this.endIndex;
		this.endIndex = this.__getEndIndex(this.startIndex, posInfo, this.cntW);
		if (this.hideMode) {
			for (var i = this.startIndex, n = this.endIndex; i < n; i ++) {
				$tabs.$(i, '$show');	
			}
		}
		var toX = - posInfo[this.startIndex];
		if (this.useEffect) {
			this.$long.horMoveTo(toX, this.sets.effectSets);
		} else {
			this.$long.css('left:' + toX + 'px');
		}
		this.hasNav && this.__setBtnStatus();
	},
	__preGroup : function () {
		var $tabs = this.$tabs, posInfo = this.posInfo;
		if (this.startIndex == 0) return;
		this.startIndex = this.__getStartIndex(this.startIndex, posInfo, this.cntW);
		this.endIndex = this.__getEndIndex(this.startIndex, posInfo, this.cntW);
		var toX = - posInfo[this.startIndex];
		var _t = this, end = this.endIndex;
		var onFinish = this.hideMode && function(){
			for (var i =	 end, len = _t.$tabs.length; i < len; i ++) {
				_t.$tabs.$(i, '$hide');	
			}
		};
		if (this.useEffect) {
			var effect = {onRemove:onFinish};
			$.extend(effect,  this.sets.effectSets || {});
			this.$long.horMoveTo(toX, effect);
		} else {
			this.$long.css('left:' + toX + 'px');	
			this.hideMode && onFinish();
		}
		this.hasNav && this.__setBtnStatus();
	},
	__setBtnStatus : function (start, end) {
		var start = this.startIndex, end = this.endIndex;
		if (this.sets.navBtnsInfo) {
			var info = this.sets.navBtnsInfo;
			var $prebtn = info.$pre, $nextbtn = info.$next, dc = info.disabledClass;
			if (start == 0 && !$prebtn.$('$$class', '@' + dc)) {
				$prebtn.$('$class', '+' + dc);	
			} else if (start > 0 && $prebtn.$('$$class', '@' + dc)){
				$prebtn.$('$class', '-' + dc);
			}
			if (end == this.$tabs.length && !$nextbtn.$('$$class', '@' + dc)) {
				$nextbtn.$('$class', '+' + dc);	
			} else if (end < this.$tabs.length && $nextbtn.$('$$class', '@' + dc)){
				$nextbtn.$('$class', '-' + dc);
			}
		}	
	},
	__getEndIndex : function (start, posInfo, w) {
		var startX = posInfo[start];
		for (var i = start + 1, n = posInfo.length; i < n; i ++) {
			if (posInfo[i] - startX > w) return i - 1;
		}
		return posInfo.length - 1;
	},
	__getStartIndex : function (end, posInfo, w) {
		var endX = posInfo[end];
		for (var i = end - 1; i >= 0; i --) {
			if (endX - posInfo[i] > w) return i + 1;	
		}
		return 0;
	}
});